package com.lap.permission.component;

import com.fasterxml.jackson.core.type.TypeReference;
import com.lap.framework.tools.JsonUtil;
import com.lap.permission.enums.IpRound;
import com.lap.permission.tools.AddressConstants;
import io.github.resilience4j.circuitbreaker.annotation.CircuitBreaker;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.Map;
import java.util.Set;

@Slf4j
@Component
@RequiredArgsConstructor
public class Ip2AddressHelper {

    private static final Set<String> NATIVE_IPS = Set.of("localhost", "127.0.0.1", "::1");

    @Qualifier("ipRestTemplate")
    private final RestTemplate restTemplate;

    @Value("${ip.url:https://whois.pconline.com.cn/ipJson.jsp?json=true&ip={ip}}")
    private String url;

    /**
     * 根据ip获取行政区域名称
     *
     * @param ip ip
     * @return 行政区域
     */
    public String getAddress(String ip) {
        if (StringUtils.isBlank(ip)) {
            return AddressConstants.UNKNOWN;
        }

        if (NATIVE_IPS.contains(ip)) {
            return AddressConstants.NATIVE_ADDRESS;
        }

        if (IpRound.validIp(ip)) {
            return AddressConstants.LOCAL_ADDRESS;
        }

        try {
            return callRemote(ip);
        } catch (Exception e) {
            log.warn("Remote IP query failed, message:{}", e.getLocalizedMessage());
        }
        return AddressConstants.UNKNOWN;
    }

    @CircuitBreaker(name = "permissionBreaker", fallbackMethod = "fallback")
    public String callRemote(String ip) {
        String resultJson = restTemplate.getForObject(url, String.class, ip);
        Map<String, Object> map = JsonUtil.toObject(resultJson, new TypeReference<>() {
        });

        if (map != null) {
            Object addrObj = map.get("addr");
            if (addrObj instanceof String addrStr && StringUtils.isNotBlank(addrStr)) {
                return addrStr;
            }
        }
        return AddressConstants.UNKNOWN;
    }

    public String fallback(String ip, Throwable e) {
        log.warn("CircuitBreaker triggered for IP: {},{}", ip, e.getLocalizedMessage());
        return AddressConstants.UNKNOWN;
    }

}
